package org.finesys.common.excel.aop;

import java.io.InputStream;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.finesys.common.excel.annotaion.RequestExcel;
import org.finesys.common.excel.converter.DictTypeConverter;
import org.finesys.common.excel.converter.LocalDateStringConverter;
import org.finesys.common.excel.converter.LocalDateTimeStringConverter;
import org.finesys.common.excel.converter.LocalTimeStringConverter;
import org.finesys.common.excel.converter.LongStringConverter;
import org.finesys.common.excel.handler.DictCacheClearAnalysisEventListener;
import org.finesys.common.excel.handler.ListAnalysisEventListener;
import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;

import cn.idev.excel.EasyExcel;

/**
 * 上传excel 解析注解
 */
public class RequestExcelArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(@NonNull MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestExcel.class);
    }

    @Override
    public Object resolveArgument(@NonNull MethodParameter parameter,@Nullable ModelAndViewContainer mavContainer,@NonNull NativeWebRequest webRequest,@Nullable WebDataBinderFactory binderFactory) throws Exception {
        Class<?> parameterType = parameter.getParameterType();
        if (!parameterType.isAssignableFrom(List.class)) {
            throw new IllegalAccessException("Excel upload request resolver error,@RequestExcel parameter is not list " + parameterType);
        }
        //处理自定义 readListener
        RequestExcel requestExcel = parameter.getParameterAnnotation(RequestExcel.class);
        assert requestExcel != null;
        if(requestExcel==null){
            throw new RuntimeException("excel 解析参数异常,不存在[RequestExcel]注解！");
        }
        Class<? extends ListAnalysisEventListener<?>> readListenerClass = requestExcel.readListener();
        ListAnalysisEventListener<?> readListener = BeanUtils.instantiateClass(readListenerClass);
        // 获取请求文件流
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        assert request != null;
        if(request==null){
            throw new RuntimeException("request参数为空！");
        }
        InputStream inputStream;
        if (request instanceof MultipartRequest) {
            MultipartFile multipartFile = ((MultipartRequest) request).getFile(requestExcel.fileName());
            assert multipartFile != null;
            if(multipartFile==null){
                throw new RuntimeException("multipartFile上传文件为空");
            }
            inputStream = multipartFile.getInputStream();
        } else {
            inputStream = request.getInputStream();
        }
        // 获取目标类型
        Class<?> excelModelClass = ResolvableType.forMethodParameter(parameter).getGeneric(0).resolve();
        // 这里需要指定读用哪个 class 去读，然后读取第一个 sheet 文件流会自动关闭
        EasyExcel.read(inputStream, excelModelClass, readListener)
                .registerConverter(LocalDateTimeStringConverter.INSTANCE)
                .registerConverter(LocalDateStringConverter.INSTANCE)
                .registerConverter(LocalTimeStringConverter.INSTANCE)
                .registerConverter(LongStringConverter.INSTANCE)
                .registerConverter(DictTypeConverter.INSTANCE)
                .registerReadListener(new DictCacheClearAnalysisEventListener())
                .ignoreEmptyRow(requestExcel.ignoreEmptyRow())
                .sheet()
                .headRowNumber(requestExcel.headRowNumber())
                .doRead();
        //检验失败的数据处理
        if(binderFactory!=null&&mavContainer!=null){
            WebDataBinder dataBinder = binderFactory.createBinder(webRequest, readListener.getErrors(), "excel");
            ModelMap modelMap = mavContainer.getModel();
            modelMap.put(BindingResult.MODEL_KEY_PREFIX + "excel", dataBinder.getBindingResult());
        }
        return readListener.getList();
    }

}
